#ifndef _DATABASE_H
#define _DATABASE_H

#include "yamlHandler.h"
#include "string.h"
#include "log.h"

#define LINESPERMAP_SEARCHFILE 7
#define LINESPERMAP_CONFIGDATA 9
#define LINESPERMAP_SCORESDATA 2

using std::string;

typedef struct {
	std::string subject;
	std::string examdate;
	int score;
}SubjectScore;

typedef struct{
    //保存在快速检索表里的基本信息
    std::string id;
    std::string name;
    std::string username;
    std::string password;
    std::string major;
    std::string grade;
    std::string _class;
    //保存在数据库中的具体信息
    std::string sex;
    std::string phone;
    std::string email;
    std::string birthday;
    std::string pid;
    std::string address;
    std::string remark;
    std::vector<SubjectScore> scores;
} StuDataStruct;

//学生信息检索表
class SearchList : public YamlHandler
{
public:
    //显式调用父类的构造函数
    SearchList() : YamlHandler(LINESPERMAP_SEARCHFILE){
        YamlHandler::loadFile("./data/id_name.yaml");
    }
    bool update(StuDataStruct new_config);
    int searchStudent(std::string lable, std::string key, StuDataStruct& stu_data);
};

//管理每个班级的科目
class SubjectConfig : public YamlHandler
{
    std::vector<SubjectScore> subjects;
public:
    SubjectConfig() : YamlHandler(4){}
    void setClass(std::string major, std::string grade, std::string _class);
    void setClass(std::string msg);
    void addSubject(std::string subject, int maxscore, int passscore, std::string examedate);
    void addSubject(std::string msg);
    std::vector<SubjectScore> getTotalSubjects();
};

class DataBaseRW : public YamlHandler
{
protected:
    string student_id;
    virtual string readLable(string lable) = 0;
    virtual bool writeLable(string lable, string content) = 0;
    virtual bool loadData(StuDataStruct &stu_data) = 0;
public: 
    DataBaseRW(int lines_per_map):YamlHandler(lines_per_map){}
    virtual bool setStudent(StuDataStruct stu_data) = 0;
    static string zipData(StuDataStruct stu_data);
    static string zipScoreData(StuDataStruct stu_data);
    static string zipSubjectData(std::vector<SubjectScore> subjects);
    static void unzipData(string msg, StuDataStruct &stu_data);
    static void unzipScoreData(string msg, StuDataStruct &stu_data);
    static void unzipSubjectData(string msg, std::vector<SubjectScore> subjects);

};

class StuConfigDB : public DataBaseRW
{
private:
    bool flag_stu_reset;
    bool studentisReset();
public:
    StuConfigDB();
    ~StuConfigDB();
    int index();
    bool setStudent(StuDataStruct stu_data);
    string readLable(string lable);
    bool writeLable(string lable, string content);
    bool loadData(StuDataStruct &stu_data);
    bool removeStudent();
};

class StuScoreDB : public DataBaseRW
{    
private:
    SubjectConfig p_subject_db;
public:
    StuScoreDB();
    ~StuScoreDB();
    int index(string subject);
    bool setStudent(StuDataStruct stu_data);
    string readLable(string lable);
    bool writeLable(string lable, string content);
    
    SubjectScore readSubjectData(string subject);
    bool loadData(StuDataStruct &stu_data);
    bool fillNewDataFile();
    bool removeStudent();
};

class Student
{
private:
    StuConfigDB p_config_db;
    StuScoreDB p_scores_db;
    StuDataStruct p_stu_data;
public:
    Student(){}
    Student(const Student &stu){
        this->p_stu_data = stu.p_stu_data;
    }
    Student(string id);
    Student(StuDataStruct stu_data);
    StuDataStruct getStuData() const;
    bool resetStudent(StuDataStruct stu_data);
    bool updateConfig(StuDataStruct stu_data);
    bool updateScores(StuDataStruct stu_data);
    bool newStudent(StuDataStruct stu_data);
    bool isExist();
};

class Aclass
{
private:
    string major;
    string grade;
    string _class;
    std::vector<Student> students;
public:
    Aclass(string msg);
    int totalStudent();
    int totalSubject();
    string getZipMsg(int index);
    string getShortConfig(int index);
};

bool operator == (StuDataStruct a, StuDataStruct b);

extern SearchList g_search_db;

#endif
